package com.lagou.sqlSession;

import com.lagou.config.BoundSql;
import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;
import com.lagou.utils.GenericTokenParser;
import com.lagou.utils.ParameterMapping;
import com.lagou.utils.ParameterMappingTokenHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author stevejson
 */
public class SimpleExecutor implements Executor {

    private PreparedStatement preparedStatement(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        //获取连接
        Connection connection = configuration.getDataSource().getConnection();
        //生成sql
        String sql = mappedStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);
        //预处理对象
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        //设置参数
        String parameterType = mappedStatement.getParameterType();
        //查询参数的类
        Class<?> parameterClass = getClassType(parameterType);

        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String content = parameterMapping.getContent();
            //反射
            Field declaredField = parameterClass.getDeclaredField(content);
            //防止私有  暴力方位
            declaredField.setAccessible(true);
            Object o = declaredField.get(params[0]);
            preparedStatement.setObject(i + 1, o);

        }

        System.out.println(sql);
        return preparedStatement;

    }

    private <E> List<E> executeWithResultHandler(MappedStatement mappedStatement, ResultSet resultSet) throws Exception {
        String resultType = mappedStatement.getResultType();
        Class<?> resultTypeClass = getClassType(resultType);
        //执行sql
        //封装结果集
        Field[] declaredFields = resultTypeClass.getDeclaredFields();
        List<String> fields = new ArrayList<>();
        for (Field field : declaredFields) {
            fields.add(field.getName());
        }
        List<E> arrayList = new ArrayList<>();

        //（ResultSet 对象具有指向其当前数据行的光标。 最初，光标被置于第一行之前。调用 next() 方法将光标移动到下一行；next()方法一开始是处于第一行之前，即beforeFirst，第一次使用next()就将指针指向返回结果集的第一行。每使用一次next()，指针就指向下一行）
        while (resultSet.next()) {
            Object o = resultTypeClass.getDeclaredConstructor().newInstance();

            ResultSetMetaData metaData = resultSet.getMetaData();

            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                String columnName = metaData.getColumnName(i);
                Object value = resultSet.getObject(columnName);
                //内省
                if (fields.contains(columnName)) {
                    PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                    Method writeMethod = propertyDescriptor.getWriteMethod();
                    writeMethod.invoke(o, value);
                }

            }

            arrayList.add((E) o);

        }
        return arrayList;

    }

    private int runWithRowCountResult(PreparedStatement preparedStatement) throws SQLException {
        return preparedStatement.executeUpdate();
    }


    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        PreparedStatement preparedStatement = preparedStatement(configuration, mappedStatement, params);
        ResultSet resultSet = preparedStatement.executeQuery();
        return executeWithResultHandler(mappedStatement, resultSet);
    }

    @Override
    public int update(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        PreparedStatement preparedStatement = preparedStatement(configuration, mappedStatement, params);
        return runWithRowCountResult(preparedStatement);
    }

    private Class<?> getClassType(String path) throws ClassNotFoundException {
        if (null == path) {
            return null;
        }
        return Class.forName(path);
    }

    /**
     * #{} 换成？，   解析出里面的值
     *
     * @param sql sql
     * @return sql
     */
    private BoundSql getBoundSql(String sql) {
        //标记处理类
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        // sql
        String parseSql = genericTokenParser.parse(sql);
        //#{}里的名称
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        return new BoundSql(parseSql, parameterMappings);
    }
}
